package com.zmj.common.lock;

import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.concurrent.TimeUnit;

/**
 * @author zmj
 * @date 2021-12-09 15:04
 */
@Component
@Slf4j
public class RedissonLock implements DistributedLock {

    @Resource
    private RedissonClient redissonClient;


    @Override
    public RLock lock(String lockKey) {
        RLock lock = redissonClient.getLock(lockKey);
        lock.lock();
        return lock;
    }


    @Override
    public RLock lock(String lockKey, int timeout) {
        RLock lock = redissonClient.getLock(lockKey);
        lock.lock(timeout, TimeUnit.SECONDS);
        return lock;
    }


    @Override
    public RLock lock(String lockKey, TimeUnit unit, int timeout) {
        RLock lock = redissonClient.getLock(lockKey);
        lock.lock(timeout, unit);
        return lock;
    }


    @Override
    public boolean tryLock(String lockKey, TimeUnit unit, int waitTime, int leaseTime) {
        RLock lock = redissonClient.getLock(lockKey);
        try {
            return lock.tryLock(waitTime, leaseTime, unit);
        } catch (InterruptedException e) {
            log.error("tryLock：获取锁异常，lockKey :[{}] ", lockKey, e);
            return false;
        }
    }


    @Override
    public boolean tryWatchDogLock(String lockKey, TimeUnit unit, int waitTime) {
        RLock lock = redissonClient.getLock(lockKey);
        try {
            return lock.tryLock(waitTime, unit);
        } catch (InterruptedException e) {
            log.error("tryWatchDogLock：获取锁异常，lockKey :[{}] ", lockKey, e);
            return false;
        }
    }

    @Override
    public RLock watchDogLock(String lockKey, TimeUnit unit, int waitTime) {
        RLock lock = redissonClient.getLock(lockKey);
        try {
            if (lock.tryLock(waitTime, unit)) {
                return lock;
            }
        } catch (InterruptedException e) {
            log.error("tryWatchDogLockReturnLock：获取锁异常，lockKey :[{}] ", lockKey, e);
            return null;
        }
        return null;
    }

    /**
     * 根据key释放锁
     *
     * @param lockKey
     */
    @Override
    public void unlock(String lockKey) {
        RLock lock = redissonClient.getLock(lockKey);
        if (lock == null) {
            log.error("unlock：error，lockKey :[{}]", lockKey);
            throw new RuntimeException("unlock：获取锁释放，lockKey :" + lockKey);
        }
        if (lock.isLocked() && lock.isHeldByCurrentThread()) {
            lock.unlock();
        } else {
            log.error("释放不属于当前线程锁！ lockKey is:[{}]", lockKey);
            throw new RuntimeException("释放不属于当前线程锁 !，lockKey :" + lockKey);
        }
    }

    /**
     * 根据锁对象释放锁
     *
     * @param lock
     */
    @Override
    public void unlock(RLock lock) {
        try {
            lock.unlock();
        } catch (Exception e) {
            log.error("unlock：error");
            throw new RuntimeException("unlock：error", e);
        }
    }
}
